package 字节笔试;

/**
 @author fujiangnan
 @create 2021-11-12-15-35
 @desc ...
 */
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main1 {
    static long[][] dp;
    static int[] positionNum;
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int a = Integer.parseInt(st.nextToken());
        int b = Integer.parseInt(st.nextToken());
        int aa = Math.min(a,b);
        int bb = Math.max(a,b);
        //因为问的是闭区间,所以对于[L,R],需要的结果是F(R)和F(L-1).
        long aResult = getCnt(aa-1);
        long bResult = getCnt(bb);
        System.out.println(bResult-aResult);
    }

    private static long getCnt(int num){
        positionNum = new int[11];//这里记录数字地每一位,到数组positionNum中
        int index = 0;
        while (num>0){
            positionNum[index++] = num%10;
            num /= 10;
        }
        //因为给定数字的范围最大不超过2亿,所以数字位数不超过9位,这里第一维度使用了11
        //因为第二维代表数字的取值范围,所以最多就是0~9,一共10位.
        dp = new long[11][10];
        //将dp数组初始化为-1.因为后续需要记忆化搜索,通过初始化的-1,来表示,某个状态没有被记录到
        for(int i = 0;i<dp.length;i++){
            Arrays.fill(dp[i],-1);
        }
        return dfs(index-1,0,true,true);
    }
    //通过dfs,进行动态规划过程.
    //position:当前数字是第几位,对应于A[i][j]中的i
    //preNum:当前位置的前一位是哪个数字,对应于A[i][j]中的j
    //isLimit:当前位置之前的所有数字位置,是否填入了它们能够达到的最大值
    //lead:前导零.当前位置之前所有位置,是否都为零.
    private static long dfs(int position, int preNum, boolean isLimit,boolean lead) {
        //如果搜索到了-1,说明每一位都被搜索到了,dfs可以在这里结束.
        if(position < 0){
            return 1;
        }
        //用于记录结果
        long result = 0;
        //记忆化的步骤.
        //1.如果前面位置填写的数字,没有达到最大值
        //2.dp[position][preNum]这个状态之前有过记录
        //3.前面数字全部都不是零
        //这种状态说明之前dfs时,已经计算过,这里直接使用.
        if(!isLimit && dp[position][preNum]!=-1 && !lead){
            return dp[position][preNum];
        }
        //如果position位置之前的所有数字都为它们位置的最大值,
        //那么当前位置最大只能够是读取的数字的当前位置的值
        //否则,这一位能够填写0~9,因为这种情况下不管怎么填写,数字都不会超过给定范围.
        int maxNum = isLimit?positionNum[position]:9;
        int abs;
        for(int i = 0;i<=maxNum;i++){
            abs = Math.abs(i-preNum);
            //条件:相邻两个数字之间的差值必须不小于2,并且是没有前导零的情况
            //如果有前导零,那么就不需要这个条件.
            if(abs<2 && !lead){
                continue;
            }
            //下面进行的都是下一位的dfs.分类了不同情况,不同情况下,dfs的第三第四个参数不同
            //当前位置填写了最大的数字,并且前面的数字也填写成为了当前位置最大的数字
            if(i == maxNum && isLimit){
                result += dfs(position-1,i,true,false);
            }
            //当前位置取值不是0或者没有前导零
            //1.如果没有前导零,无论当前位取值如何,该状态表示的数字都不会是当前位置之前全部是零的情况
            //2.如果当前位置取值非零,那么之后一定不是前导零的状态了
            else if(i != 0 || !lead){
                result+= dfs(position-1,i,false,false);
            }
            //和上面的状态相反,这里就表示了,是前导零的状态.
            else{
                result += dfs(position-1,i,false,true);
            }
        }
        //这里针对一般的情况,进行了结果记录,以便后续使用
        //一般情况的条件:
        //1.各个位置不是最大取值
        //2.不包含前导零状态
        if(!isLimit && !lead){
            dp[position][preNum] = result;
        }
        return result;
    }
}


